home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue25 / mfboid1s / MFBOID1S.ZIP / uTMovableEngine.pas < prev   
Encoding:
Pascal/Delphi Source File  |  1997-07-08  |  11.1 KB  |  424 lines

  1. unit uTMovableEngine;
  2.  
  3. interface
  4.  
  5. uses
  6.     Graphics, Classes, Forms, Windows, uTMovable;
  7.  
  8. type
  9.   TWithinResultTypes = (wrtBefore,wrtWithin,wrtWithinOutside,wrtAfter);
  10.   
  11.   TMovableEngine = class
  12.     MovableList            : Tlist;
  13.     ObstacleList        : TList;
  14.     Canvas                    : TCanvas;
  15.  
  16.     bBlanking                : boolean;
  17.  
  18.     MaxSpeed                 : real;
  19.       MaxSpeedChange     : real;
  20.       SensorDistance     : real;
  21.     Application            : TApplication;
  22.  
  23.     LineLength            : real;
  24.  
  25.     procedure RunStep;virtual;
  26.     procedure GetClosestMovables(MyMovable : TMovable; CloseList : TList);virtual;
  27.     function GetClosestObstacle(MyMovable : TMovable) : TMovable;virtual;
  28.     constructor Create(OutputCanvas : TCanvas);virtual;
  29.     procedure SetNewCanvas(OutputCanvas : TCanvas);
  30.     destructor Destroy;virtual;
  31.   end;
  32.  
  33.   procedure ClearArena(Canvas : TCanvas);
  34.  
  35. implementation
  36.  
  37. //******************************************************************************
  38. procedure ClearArena(Canvas : TCanvas);
  39. begin
  40.     Canvas.Pen.Color := clBlack;
  41.   Canvas.Brush.Color := clBlack;
  42.     Canvas.FillRect(Canvas.ClipRect);
  43. end;
  44.  
  45. //******************************************************************************
  46. function CompareMovable(Item1, Item2: Pointer): Integer;
  47. var
  48.   Movable1, Movable2  : TMovable;
  49.   iTemp               : integer;
  50. begin
  51.   Movable1 := Item1;
  52.   Movable2 := Item2;
  53.  
  54.   iTemp := trunc(Movable1.X-Movable2.X);
  55.  
  56.   if iTemp = 0 then
  57.     iTemp := trunc(Movable1.Y-Movable2.Y);
  58.  
  59.   CompareMovable := iTemp;
  60. end;
  61.  
  62. //******************************************************************************
  63. function BinSearch(TestList : TList; FindObj : Pointer; CompFun : TListSortCompare;iStartBottom,iStartTop : integer) : integer;
  64. var
  65.   Top,Bottom,Test     : integer;
  66.   TestResult          : integer;
  67.   bItsAtTheBottom     : boolean;
  68. begin
  69.   Bottom := iStartBottom;
  70.  
  71.   if iStartTop <> -1 then
  72.     Top := iStartTop
  73.   else
  74.     Top := TestList.Count-1;
  75.   TestResult := -1;
  76.   bItsAtTheBottom := false;
  77.  
  78.   while not bItsAtTheBottom and (Top-Bottom > 1) {and (TestResult <> 0)} do
  79.   begin
  80.     Test := (Bottom+Top) div 2;
  81.     TestResult := CompFun(FindObj, TestList[Test]);
  82.     if TestResult <= 0 then
  83.       Top := Test
  84.     else
  85.     begin
  86.       Bottom := Test;
  87.  
  88.       bItsAtTheBottom := (TestResult = 0);
  89.     end;
  90.   end;
  91.  
  92.   if bItsAtTheBottom then
  93.     BinSearch := Bottom
  94.   else
  95.     BinSearch := Top;
  96. end;
  97.  
  98. //******************************************************************************
  99. function IsWithinRange(Movable : TMovable; Range : TRect) : TWithinResultTypes;
  100. begin
  101.  
  102.   //TWithinResultTypes = (wrtBefore,wrtWithin,wrtWithinOutside,wrtAfter);
  103.   if (Movable.X < Range.Left) then
  104.     IsWithinRange := wrtBefore
  105.   else
  106.   if (Movable.X > Range.Right) then
  107.     IsWithinRange := wrtAfter
  108.   else
  109.   if (Movable.X >= Range.Left) and (Movable.X <= Range.Right) and
  110.     (Movable.Y <= Range.Bottom) and (Movable.Y >= Range.Top) then
  111.     IsWithinRange := wrtWithin
  112.   else
  113.     IsWithinRange := wrtWithinOutside;
  114. end;
  115.  
  116. //******************************************************************************
  117. constructor TMovableEngine.Create(OutputCanvas : TCanvas);
  118. var
  119.   i                 : integer;
  120. begin
  121.   MovableList := TList.Create;
  122.   ObstacleList := TList.Create;
  123.  
  124.   Canvas := OutputCanvas;
  125.  
  126.   bBlanking := true;
  127.  
  128.   MaxSpeed := 5;
  129.   MaxSpeedChange := 0.09;
  130.   SensorDistance := 60;
  131.  
  132.  
  133.   LineLength := 3;
  134. end;
  135.  
  136. //******************************************************************************
  137. procedure TMovableEngine.SetNewCanvas(OutputCanvas : TCanvas);
  138. var
  139.     i : integer;
  140. begin
  141.     Canvas := OutputCanvas;
  142. {  for i := 0 to MovableList.Count - 1 do
  143.     TMovable(MovableList[i]).Canvas := OutputCanvas;
  144.  
  145.      for i := 0 to MovableList.Count - 1 do
  146.     TMovable(ObstacleList[i]).Canvas := OutputCanvas;}
  147. end;
  148.  
  149. //******************************************************************************
  150. destructor TMovableEngine.Destroy;
  151. var
  152.   i : integer;
  153. begin
  154.   for i := 0 to MovableList.Count - 1 do
  155.     TMovable(MovableList[i]).Destroy;
  156.  
  157.      for i := 0 to ObstacleList.Count - 1 do
  158.     TMovable(ObstacleList[i]).Destroy;
  159.  
  160.      MovableList.Destroy;
  161.   ObstacleList.Destroy;
  162. end;
  163.  
  164. //******************************************************************************
  165. procedure TMovableEngine.GetClosestMovables(MyMovable : TMovable; CloseList : TList);
  166. // This function is fairly complicated, if you need to alter it, be very careful,
  167. // or use one of the three other versions included at the end of this file. They're
  168. // all slower than this version, but that's mostly noticable when the number of
  169. // movables are in the hundreds.
  170. //
  171. //function GetMovablesWithinRangeSmarter(MovableList : TList; Range : TRect) : integer;
  172. var
  173.   i             : integer;
  174.   LastPosition  : integer;
  175.   Test          : TMovable;
  176.   TestMovable   : TMovable;
  177.   WithinResult  : TWithinResultTypes;
  178.   iFound        : integer;
  179.   LastX         : real;
  180.   Range                    : TRect;
  181.   SensHalf            : real;
  182. begin
  183.   Test := TMovable.Create(nil);
  184.  
  185.   SensHalf := SensorDistance/2;
  186.  
  187.   with MyMovable do
  188.       Range := Rect(trunc(X-SensHalf),trunc(Y-SensHalf),trunc(X+SensHalf),trunc(Y+SensHalf));
  189.  
  190.   if Range.Left < 0 then Range.Left := 0;
  191.     if Range.Top < 0 then Range.Top := 0;
  192.  
  193.   Test.X := Range.Left;
  194.   Test.Y := Range.Top;
  195.  
  196.   TestMovable := Test;
  197.   iFound := 0;
  198.  
  199.   i := BinSearch(MovableList,Test,CompareMovable,0,-1);
  200.  
  201.   Test.X := Range.Right+1;
  202.   LastPosition := BinSearch(MovableList,Test,CompareMovable,0,-1);
  203.  
  204.   LastX := Range.Left;
  205.   while (i < MovableList.Count) and (WithinResult <> wrtAfter) and
  206.         (i < LastPosition)  do
  207.   begin
  208.       TestMovable := MovableList[i];
  209.     WithinResult := IsWithinRange(TestMovable,Range);
  210.     if WithinResult = wrtWithin then
  211.     begin
  212.       inc(iFound);
  213.       LastX := TestMovable.X;
  214.  
  215.             if TestMovable <> MyMovable then
  216.             begin
  217.           TestMovable.DistanceSquared := sqr(TestMovable.X-MyMovable.X) +
  218.             sqr(TestMovable.Y-MyMovable.Y);
  219.  
  220.           CloseList.Add(TestMovable);
  221.       end;
  222.       
  223.       inc(i);
  224.     end else
  225.     if WithinResult = wrtWithinOutside then
  226.     begin
  227.       Test.X := LastX+1;
  228.       LastX := lastX+1;
  229.       i := BinSearch(MovableList,Test,CompareMovable,i,LastPosition);
  230.     end else inc(i);
  231.   end;
  232.  
  233.   Test.Destroy;
  234. //  result := iFound;
  235. end;//}
  236.  
  237. //******************************************************************************
  238. function TMovableEngine.GetClosestObstacle(MyMovable : TMovable) : TMovable;
  239. var
  240.   i               : integer;
  241.   x,y             : real;
  242.   dx,dy                    : real;
  243.   Range            : real;
  244.   DistSQR          : real;
  245.   TestObstacle     : TMovable;
  246.   HDist         : real;
  247.   fClosestSoFar : real;
  248. begin
  249.   X := MyMovable.X;
  250.   Y := MyMovable.Y;
  251.   fClosestSoFar := 0;
  252.  
  253.   // Assume none will be found!
  254.   GetClosestObstacle := nil;
  255.  
  256.   for i := 0 to ObstacleList.Count - 1 do
  257.   begin
  258.     TestObstacle := ObstacleList[i];
  259.     dx := Abs(TestObstacle.x-x);
  260.     dy := abs(TestObstacle.y-y);
  261.  
  262.       DistSQR := sqr(dx)+sqr(dy);
  263.        if (DistSQR < fClosestSoFar) or (fClosestSoFar=0) then
  264.     begin
  265.         fClosestSoFar := DistSQR;
  266.       GetClosestObstacle := TestObstacle;
  267.        end;
  268.   end;
  269. end;
  270.  
  271. //******************************************************************************
  272. procedure TMovableEngine.RunStep;
  273. var
  274.   i                 : integer;
  275.   ClosestBoids      : TList;
  276.   Obstacle                    : TMovable;
  277. begin
  278.   ClosestBoids := TList.Create;
  279.  
  280.   if ObstacleList.Count <> 0 then
  281.       Obstacle := ObstacleList[0];
  282.  
  283.     MovableList.Sort(CompareMovable);
  284.  
  285.   for i := 0 to MovableList.Count - 1 do
  286.   begin
  287.     GetClosestMovables(TMovable(MovableList[i]),ClosestBoids);
  288.  
  289.         Obstacle := GetClosestObstacle(TMovable(MovableList[i]));
  290.  
  291.     if (Obstacle <> nil) and (not Obstacle.bActive) then
  292.           Obstacle := nil;
  293.  
  294.         TMovable(MovableList[i]).PrepareToMove(ClosestBoids, Obstacle,Canvas);
  295.  
  296.     ClosestBoids.Clear;
  297.   end;
  298.  
  299.   Application.ProcessMessages;
  300.  
  301.   for i := 0 to ObstacleList.Count - 1 do
  302.     TMovable(ObstacleList[i]).Move(Canvas);
  303.  
  304.   for i := 0 to MovableList.Count - 1 do
  305.     TMovable(MovableList[i]).Move(Canvas);
  306.  
  307.   if bBlanking then
  308.         ClearArena(Canvas);
  309.  
  310.   for i := 0 to ObstacleList.Count - 1 do
  311.     TMovable(ObstacleList[i]).Draw(Canvas);//}
  312.  
  313.   for i := 0 to MovableList.Count - 1 do
  314.     TMovable(MovableList[i]).Draw(Canvas); //}*)
  315.  
  316.   ClosestBoids.Destroy;
  317. end;
  318.  
  319. //******************************************************************************
  320. //Original version
  321. {procedure TMovableEngine.GetClosestMovables(MyMovable : TMovable; CloseList : TList);
  322. var
  323.   i               : integer;
  324.   x,y             : real;
  325.   dx,dy                    : real;
  326.   Range            : real;
  327.   DistSQR          : real;
  328.   TestMovable      : TMovable;
  329.   HDist         : real;
  330. begin
  331.   Range := sqr(SensorDistance);
  332.   HDist := SensorDistance/2;
  333.  
  334.   X := MyMovable.X;
  335.   Y := MyMovable.Y;
  336.  
  337.   for i := 0 to MovableList.Count - 1 do
  338.   begin
  339.     TestMovable := MovableList[i];
  340.     dx := Abs(TestMovable.x-x);
  341.     dy := abs(TestMovable.y-y);
  342.  
  343.     //if (dx + dy)*10 < Range then
  344.     if Within(dx, -HDist, +HDist) and
  345.        Within(dy, -HDist, +HDist) then
  346.     begin
  347.         DistSQR := (sqr(dx)+sqr(dy));
  348.            if (TestMovable <> MyMovable) and
  349.            (DistSQR < Range) then
  350.         begin
  351.           TestMovable.DistanceSquared := DistSQR;
  352.              CloseList.Add(TestMovable);
  353.         end;
  354.     end;
  355.   end;
  356. end;//}
  357.  
  358.  
  359. //******************************************************************************
  360. {Original version remade
  361. function GetMovablesWithinRange(MovableList : TList; Range : TRect) : integer;
  362. var
  363.   i             : integer;
  364.   Test          : TMovable;
  365.   WithinResult  : TWithinResultTypes;
  366.   iFound        : integer;
  367. begin
  368.   Test := TMovable.CreateXY(Range.Left, Range.Top);
  369.  
  370.   iFound := 0;
  371.  
  372.   i := BinSearch(MovableList,Test,CompareMovable,0,-1);
  373. //  AddText(intTostr(i));
  374.  
  375.   while (i < MovableList.Count) and (WithinResult <> wrtAfter)  do
  376.   begin
  377.     WithinResult := IsWithinRange(TMovable(MovableList[i]),Range);
  378.     if WithinResult = wrtWithin then
  379.       inc(iFound);
  380.  
  381.     inc(i);
  382.   end;
  383.  
  384.   result := iFound;
  385.  
  386.   Test.Destroy;
  387. end;}
  388.  
  389. //******************************************************************************
  390. {Slightly smarter version}
  391. (*procedure TMovableEngine.GetClosestMovables(MyMovable : TMovable; CloseList : TList);
  392. //function GetMovablesWithinRangeOld(MovableList : TList; Range : TRect) : integer;
  393. var
  394.   i             : integer;
  395.   WithinResult  : TWithinResultTypes;
  396.   iFound        : integer;
  397.   Range                    : TRect;
  398.   SensHalf            : real;
  399. begin
  400.   SensHalf := SensorDistance/2;
  401.  
  402.   with MyMovable do
  403.       Range := Rect(trunc(X-SensHalf),trunc(Y-SensHalf),trunc(X+SensHalf),trunc(Y+SensHalf));
  404.  
  405.   if Range.Left < 0 then Range.Left := 0;
  406.     if Range.Top < 0 then Range.Top := 0;
  407.  
  408.   iFound := 0;
  409.   for i := 0 to MovableList.Count - 1 do
  410.       if MyMovable <> TMovable(MovableList[i]) then
  411.     begin
  412.       WithinResult := IsWithinRange(TMovable(MovableList[i]),Range);
  413.       if WithinResult = wrtWithin then
  414.       begin
  415.         TMovable(MovableList[i]).DistanceSquared :=
  416.           sqr(TMovable(MovableList[i]).X-MyMovable.X) +
  417.           sqr(TMovable(MovableList[i]).Y-MyMovable.Y);
  418.         CloseList.Add(MovableList[i]);
  419.       end;
  420.     end;
  421. end;// *)
  422.  
  423. end.
  424.